package com.gzsxy.esjy.thread;


import com.gzsxy.esjy.response.NettyHttpResponse;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

/**
 * 文件处理
 * @author hezhiyuan
 *
 */
public class FileOperateRunnable implements Runnable{
	
	private final File file;
	private ChannelHandlerContext ctx;
	private final Channel channel ;
	private final boolean keepLive;
	
	private final boolean needResponse ;
	
	public FileOperateRunnable(File file, ChannelHandlerContext ctx, boolean keepLive) {
		super();
		this.file = file;
		this.ctx = ctx;
		this.channel = ctx.channel();
		this.keepLive = keepLive;
		this.needResponse = true ;
	}
	
	public FileOperateRunnable(File file, Channel channel, boolean keepLive) {
		super();
		this.file = file;
		this.channel = channel;
		this.keepLive = keepLive;
		this.needResponse = false ;
	}

	@Override
	public void run() {
		try {
			service() ;
		}catch(Exception e) {
			ChannelFuture writeAndFlush = channel.writeAndFlush(NettyHttpResponse.doExceptionResponse(e, "utf-8"));
			if(!keepLive) {
				writeAndFlush.addListener(ChannelFutureListener.CLOSE);
			}
		}
	}
	
	
	
	/**
	 * 业务
	 * @throws Exception
	 */
	private void service() throws Exception {
		//随机文件读写类
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r") ;
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
 
        //获取文件长度
        long fileLength = randomAccessFile.length();
        //设置响应信息
//        response.headers().set(HttpHeaderNames.TRANSFER_ENCODING,"chunked") ;
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH,fileLength) ;
        response.headers().set(HttpHeaderNames.ACCEPT_RANGES,"bytes") ;

        response.headers().add("Access-Control-Allow-Origin", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client");
        response.headers().add("Access-Control-Allow-Methods", "*");
        response.headers().add("Access-Control-Max-Age", "18000L");
        response.headers().add("Access-Control-Allow-Headers", "*");
        response.headers().add("Access-Control-Expose-Headers", "*");
        response.headers().add("Access-Control-Allow-Credentials", "true");
        
        
        
        //设置响应头
        setContentTypeHeader(response, file);
        
        //如果一直保持连接则设置响应头信息为：HttpHeaders.Values.KEEP_ALIVE
        if (!keepLive) {
        	response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
        }
        
        //进行写出
        downLoad(ctx, randomAccessFile, response, fileLength);
	}

	/**
	 * 文件下载
	 * @param ctx
	 * @param randomAccessFile
	 * @param response
	 * @param fileLength
	 * @throws IOException
	 */
	private void downLoad(ChannelHandlerContext ctx,RandomAccessFile randomAccessFile,
			HttpResponse response, long fileLength) throws IOException {
		if(needResponse) {
			channel.write(response);
		}
		//DefaultFileRegion底层实现零拷贝
		//FileChannel file底层文件的文件通道;long position数据从通道中抽取的起始位置;long count需要传递的总字节数
		channel.write(new DefaultFileRegion(randomAccessFile.getChannel(), 0, fileLength), channel.newProgressivePromise());  
        //写入并刷新
		ChannelFuture lastContentFuture = channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
       
        if (!keepLive) {
            lastContentFuture.addListener(ChannelFutureListener.CLOSE);
        }
        
	}

	/**
	 * 根据文件类型设置请求参数
	 * @param response
	 * @param file
	 */
	private static void setContentTypeHeader(HttpResponse response, File file) {
		MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
		response.headers().set(HttpHeaderNames.CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
	}
	
}
